package com.seguriapp.controller;

import static com.google.common.collect.Lists.newArrayList;

import java.util.Date;
import java.util.List;
import java.util.Map;

import net.sf.json.JSONException;
import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.seguriapp.entities.MenuLink;
import com.seguriapp.entities.MenuLinkRole;
import com.seguriapp.entities.User;
import com.seguriapp.services.SecurityService;
import com.seguriapp.util.Util;

/**
 * Represents the controller for the security of the system
 * 
 * @author Tania Gonzales(taniadgv@gmail.com)
 */
@Controller
@RequestMapping("/security")
public class SecurityController {

  private static final Logger LOGGER = Logger.getLogger(SecurityController.class);

  @Autowired
  private SecurityService securityService;

  private long totalPages;

  @RequestMapping(value = "/validateCredentials", method = RequestMethod.POST)
  @ResponseBody()
  public String getUserInitialData(@RequestBody final String credentialsJs) throws Exception {
    LOGGER.info("validate user credentials : " + credentialsJs);
    final User user = securityService.getUserInitialData(getJsonCredentialsDataFromString(credentialsJs));
    final JSONObject obj = new JSONObject();
    String str = null;
    if (user != null) {
      LOGGER.info("Correct User Login : " + user.getUsername());
      try {
        final List<MenuLink> menuLinksList;
        final Map<String, Object> userData = user.toJsonString();
        userData.put("entitiesList", securityService.getUserEntities(user.getId()));
        obj.put("userData", userData);
        LOGGER.info(obj.toString());
        if (!getNoDataFlagFromJson(credentialsJs)) {
          if (user.isAdministrator()) {
            menuLinksList = securityService.getMenuLinkListByRole(MenuLinkRole.Administrator.name());
          } else {
            menuLinksList = securityService.getMenuLinkListByRole(MenuLinkRole.User.name());
          }
          String objStr = obj.toString();
          objStr = objStr.substring(0, objStr.length() - 1);
          final String menuLinksStr = Util.parseEntityListToJson("menuLinks", menuLinksList);
          str = objStr + ", " + menuLinksStr.substring(1, menuLinksStr.length());
          // set date last logged in
          user.setLastDateLoggedIn(new Date());
          securityService.saveUser(user);
        } else {
          str = obj.toString();
        }
      } catch (JSONException e) {
        LOGGER.error("Error getting user initial data", e);
      }
    } else {
      LOGGER.info("Username or password incorrect.");
      obj.put("errorMessage", "Username or password incorrect.");
      str = obj.toString();
    }
    LOGGER.info("return : " + str);
    return str;
  }

  @RequestMapping(value = "/getMenuLinks/{menuLinkRole}", method = RequestMethod.GET)
  @ResponseBody()
  public String getMenuLinkListData(@PathVariable String menuLinkRole) throws Exception {
    final List<MenuLink> menuLinksList = securityService.getMenuLinkListByRole(menuLinkRole);
    LOGGER.info("Cantidad de Menu Links : " + menuLinksList.size());
    return Util.parseEntityListToJson("menuLinks", menuLinksList);
  }

  @RequestMapping(value = "/listUsers", method = RequestMethod.POST)
  @ResponseBody()
  public String getUsersList(final @RequestBody String searchOptionsJs) throws Exception {
    final List<User> usersList = getUsersData(searchOptionsJs);
    if (usersList != null) {
      LOGGER.info("Size of users list : " + usersList.size());
      return Util.parseEntityListToJson("users", usersList, totalPages);
    }
    return StringUtils.EMPTY;
  }

  @RequestMapping(value = "/saveUserData", method = RequestMethod.POST)
  @ResponseBody()
  public String saveUserData(@RequestBody final String userDataJs) throws Exception {
    final String errorMessage = securityService.saveUserData(getJsonCredentialsDataFromString(userDataJs));
    final JSONObject obj = new JSONObject();
    if (errorMessage != null) {
      try {
        obj.put("errorMessage", errorMessage);
        return obj.toString();
      } catch (JSONException e) {
        LOGGER.error("Error converting error message to json \n", e);
      }
    }
    return null;
  }

  private User getJsonCredentialsDataFromString(final String userDataJs) {
    if (userDataJs == null || userDataJs.isEmpty()) {
      return null;
    }
    final JSONObject root = JSONObject.fromObject(userDataJs);
    JSONObject jo = null;
    final User user = new User();
    if (root.has("userData")) {
      jo = root.getJSONObject("userData");
      if (jo.has("username") && jo.has("password")) {
        user.setUsername(jo.getString("username"));
        user.setPassword(jo.getString("password"));
        LOGGER.info("User Login : " + user.getUsername());
      }
      if (jo.has("id")) {
        user.setId(jo.getLong("id"));
        if (user.getId() == 0) {
          user.setId(null);
        }
      }
    }
    return user;
  }

  private List<User> getUsersData(final String searchOptionsJs) {
    if (searchOptionsJs == null || searchOptionsJs.isEmpty()) {
      return newArrayList();
    }
    final JSONObject root = JSONObject.fromObject(searchOptionsJs);
    if (root.has(Util.PAGE) && root.has(Util.PAGE_SIZE) && root.has(Util.ASCENDING)) {
      totalPages = securityService.getUsersTotalPages(root.getInt(Util.PAGE_SIZE));
      final String columnSort = root.has(Util.COLUMN_SORT) ? root.getString(Util.COLUMN_SORT) : null;
      return securityService.listUsersOrderByColumn(root.getInt(Util.PAGE), root.getInt(Util.PAGE_SIZE), root.getBoolean(Util.ASCENDING), columnSort);
    }
    return newArrayList();
  }

  private boolean getNoDataFlagFromJson(final String userDataJs) {
    if (userDataJs == null || userDataJs.isEmpty()) {
      return false;
    }
    final JSONObject root = JSONObject.fromObject(userDataJs);
    return root.has("getNoData") ? root.getBoolean("getNoData") : false;
  }

}
